import { useMemoizedFn } from 'ahooks';
import {
  forwardRef,
  HTMLAttributes,
  MutableRefObject,
  ReactElement,
  ReactNode,
  useEffect,
  useRef,
  useState,
} from 'react';

export type MouseActionInputProps = HTMLAttributes<HTMLDivElement> & {
  placeholder?: ReactNode;
  onActiveFocus?: VoidFunction;
  onActiveBlur?: VoidFunction;
  onClickOutside?: (e: MouseEvent, onUnregister: VoidFunction) => void;
  disabled?: boolean;
  allowSelectFromTreeView?: boolean;
  focusRef?: MutableRefObject<HTMLInputElement>;
  active?: boolean;
  setActive?: (active: boolean) => void;
  blurOnClickOut?: boolean;
  titleSuffix?: ReactElement;
};

const TREE_VIEW_ROOT_CLASS = 'ant-tree';

export const MouseActionInput = forwardRef<
  HTMLDivElement,
  MouseActionInputProps
>(
  (
    {
      placeholder,
      onActiveFocus,
      onActiveBlur,
      children,
      onClickOutside,
      disabled,
      allowSelectFromTreeView = false,
      autoFocus,
      active,
      setActive,
      blurOnClickOut = false,
      titleSuffix,
      ...rest
    },
    ref,
  ) => {
    const inputRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
      if (active == null) {
        return;
      }

      if (active) {
        register();
      } else {
        unRegister();
      }
    }, [active]);

    const register = () => {
      setIsActive(true);
      onActiveFocus?.();
    };

    const unRegister = () => {
      setIsActive(false);

      onActiveBlur?.();
    };

    const [innerIsActive, setInnerIsActive] = useState(false);

    const isActive = active ?? innerIsActive;

    const setIsActive = (val: boolean) => {
      (setActive ?? setInnerIsActive)(val);
    };

    const treeViewRef = useRef<Element[]>(
      Array.from(document.getElementsByClassName(TREE_VIEW_ROOT_CLASS)),
    );

    const clickOutside = useMemoizedFn(
      onClickOutside
        ? (e) => {
            onClickOutside(e, unRegister);
          }
        : (e: MouseEvent) => {
            if (
              Array.from((e.target as Node)?.parentNode?.children ?? [])?.some(
                (e) => e.tagName === 'CANVAS',
              ) ||
              !blurOnClickOut
            ) {
              return;
            }

            if (
              [
                inputRef.current,
                ...(allowSelectFromTreeView ? treeViewRef.current : []),
              ].every((i) => i != null && !i.contains(e.target as Node))
            ) {
              unRegister();
            }
          },
    );

    useEffect(() => {
      // capture规避input被创建前的点击事件被监听
      document.addEventListener('click', clickOutside, { capture: true });

      if (autoFocus) {
        // 待外层 csEvent setState结束再调用
        setTimeout(() => {
          register();
        });
      }

      return () => {
        document.removeEventListener('click', clickOutside, { capture: true });
        unRegister();
      };
    }, []);

    return (
      <div
        {...rest}
        className={`pick-input_base-select ${
          disabled ? 'pick-input_base-select--disabled' : ''
        } ${isActive ? 'pick-input_base-select--active' : ''} ${
          rest.className || ''
        }`}
        onClick={register}
        ref={ref ?? inputRef}
      >
        {placeholder && (
          <div className='flex justify-between'>
            <div className='pick-input_base-select__placeholder'>
              {placeholder}
            </div>
            {titleSuffix}
          </div>
        )}
        <div
          className={`overflow-y-auto ${
            placeholder
              ? 'max-h-[72px] pick-input_base-select_selections-under-placeholder'
              : 'max-h-[96px]'
          }`}
        >
          {children}
        </div>
        {/* 仅用于tab focus */}
        {/* <input
          className='fixed top-0 left-0 -z-[1000] w-0 h-0 max-w-0 max-h-0 opacity-0 cursor-none'
          onFocus={register}
        /> */}
      </div>
    );
  },
);
